CM3D2 Converter.misc_VIEW3D_PT_tools_weightpaint
1# 「3Dビュー」エリア → 「ウェイトペイント」モード → ツールシェルフ → 「ウェイトツール」パネル 2import bpy 3import bmesh 4import mathutils 5from . import common 6from . import compat 7 8 9# メニュー等に項目追加 10def menu_func(self, context): 11 icon_id = common.kiss_icon() 12 box = self.layout.box() 13 column = box.column(align=False) 14 column.prop(context.active_object.data, 'use_paint_mask_vertex', icon='VERTEXSEL', text="頂点選択モード") 15 column.operator('mesh.selected_mesh_vertex_group_blur', text="選択部をぼかす", icon_value=icon_id) 16 column.operator('mesh.selected_mesh_vertex_group_calculation', text="選択部に四則演算", icon_value=icon_id) 17 18 19@compat.BlRegister() 20class CNV_OT_selected_mesh_vertex_group_blur(bpy.types.Operator): 21 bl_idname = 'mesh.selected_mesh_vertex_group_blur' 22 bl_label = "選択部の頂点グループをぼかす" 23 bl_description = "選択メッシュの頂点グループの割り当てをぼかします" 24 bl_options = {'REGISTER', 'UNDO'} 25 26 items = [ 27 ('LINER', "リニア", "", 'LINCURVE', 1), 28 ('TRIGONOMETRIC', "スムーズ", "", 'SMOOTHCURVE', 2), 29 ] 30 smooth_method = bpy.props.EnumProperty(items=items, name="減衰タイプ", default='TRIGONOMETRIC') 31 32 selection_blur_range_multi = bpy.props.FloatProperty(name="選択をぼかす範囲倍率", default=4.0, min=0.0, max=100.0, soft_min=0.0, soft_max=100.0, step=50, precision=1) 33 selection_blur_accuracy = bpy.props.IntProperty(name="選択をぼかす分割精度", default=3, min=0, max=10, soft_min=1, soft_max=10) 34 35 items = [ 36 ('ALL', "全て", "", 'COLLAPSEMENU', 1), 37 ('ACTIVE', "アクティブのみ", "", 'LAYER_ACTIVE', 2), 38 ] 39 target_vertex_group = bpy.props.EnumProperty(items=items, name="対象頂点グループ", default='ALL') 40 items = [ 41 ('NORMAL', "通常・ぼかし", "", 'BRUSH_BLUR', 1), 42 ('ADD', "増加・拡張", "", 'BRUSH_DARKEN', 2), 43 ('SUB', "減少・縮小", "", 'BRUSH_LIGHTEN', 3), 44 ] 45 blur_mode = bpy.props.EnumProperty(items=items, name="ぼかしモード", default='NORMAL') 46 blur_range_multi = bpy.props.FloatProperty(name="ウェイトをぼかす範囲倍率", default=4.0, min=0.0, max=100.0, soft_min=0.0, soft_max=100.0, step=50, precision=1) 47 blur_count = bpy.props.IntProperty(name="ウェイトをぼかす回数", default=1, min=1, max=100, soft_min=1, soft_max=100) 48 is_vertex_group_limit_total = bpy.props.BoolProperty(name="ウェイト数を4つに制限", default=True) 49 50 @classmethod 51 def poll(cls, context): 52 ob = context.active_object 53 if ob.type == 'MESH': 54 if len(ob.vertex_groups): 55 return len(ob.data.vertices) and len(ob.data.edges) 56 return False 57 58 def invoke(self, context, event): 59 return context.window_manager.invoke_props_dialog(self) 60 61 def draw(self, context): 62 self.layout.prop(self, 'smooth_method') 63 64 self.layout.label(text="選択をぼかす", icon='UV_SYNC_SELECT') 65 self.layout.prop(self, 'selection_blur_range_multi', text="範囲 | 辺の長さの平均×") 66 self.layout.prop(self, 'selection_blur_accuracy', text="精度 (分割数)") 67 68 self.layout.label(text="頂点グループをぼかす", icon='GROUP_VERTEX') 69 self.layout.prop(self, 'target_vertex_group', text="対象グループ") 70 self.layout.prop(self, 'blur_mode', text="モード") 71 self.layout.prop(self, 'blur_range_multi', text="範囲 | 辺の長さの平均×") 72 self.layout.prop(self, 'blur_count', text="実行回数") 73 self.layout.prop(self, 'is_vertex_group_limit_total', icon='IMGDISPLAY') 74 75 def execute(self, context): 76 class EmptyClass: 77 pass 78 79 ob = context.active_object 80 me = ob.data 81 82 pre_mode = ob.mode 83 bpy.ops.object.mode_set(mode='OBJECT') 84 85 pre_selected_objects = context.selected_objects[:] 86 for selected_object in pre_selected_objects: 87 compat.set_select(selected_object, False) 88 compat.set_select(ob, True) 89 90 bpy.ops.object.duplicate(linked=False, mode='TRANSLATION') 91 92 selection_ob = context.active_object 93 selection_me = selection_ob.data 94 95 for v in selection_me.vertices: 96 if v.hide: 97 v.hide = False 98 compat.set_select(v, False) 99 for e in selection_me.edges: 100 if e.hide: 101 e.hide = False 102 compat.set_select(e, False) 103 for p in selection_me.polygons: 104 if p.hide: 105 p.hide = False 106 compat.set_select(p, False) 107 108 bpy.ops.object.mode_set(mode='EDIT') 109 bpy.ops.mesh.select_all(action='INVERT') 110 if context.tool_settings.mesh_select_mode[0]: 111 bpy.ops.mesh.delete(type='VERT') 112 elif context.tool_settings.mesh_select_mode[1]: 113 bpy.ops.mesh.delete(type='EDGE') 114 elif context.tool_settings.mesh_select_mode[2]: 115 bpy.ops.mesh.delete(type='FACE') 116 bpy.ops.mesh.select_all(action='SELECT') 117 if 1 <= self.selection_blur_accuracy: 118 # quadtriはデフォルトでFalseのため、省略(2.8では代わりにngon=Trueが追加) 119 bpy.ops.mesh.subdivide( 120 number_cuts=self.selection_blur_accuracy, 121 smoothness=0, quadcorner='INNERVERT', 122 fractal=0, fractal_along_normal=0, seed=0) 123 bpy.ops.object.mode_set(mode='OBJECT') 124 125 selection_kd = mathutils.kdtree.KDTree(len(selection_me.vertices)) 126 for v in selection_me.vertices: 127 selection_kd.insert(v.co, v.index) 128 selection_kd.balance() 129 common.remove_data([selection_ob, selection_me]) 130 131 compat.set_select(ob, True) 132 compat.set_active(context, ob) 133 134 bm = bmesh.new() 135 bm.from_mesh(me) 136 edge_lengths = [e.calc_length() for e in bm.edges] 137 bm.free() 138 edge_lengths.sort() 139 edge_lengths_center_index = int((len(edge_lengths) - 1) * 0.5) 140 average_edge_length = edge_lengths[edge_lengths_center_index] 141 selection_blur_range = average_edge_length * self.selection_blur_range_multi 142 143 vert_selection_values = [None for v in me.vertices] 144 for vert in me.vertices: 145 co, index, dist = selection_kd.find(vert.co) 146 if dist <= selection_blur_range + 0.00001: 147 if 0 < selection_blur_range: 148 if self.smooth_method == 'TRIGONOMETRIC': 149 value = common.trigonometric_smooth(1.0 - (dist / selection_blur_range)) 150 else: 151 value = 1.0 - (dist / selection_blur_range) 152 vert_selection_values[vert.index] = value 153 else: 154 vert_selection_values[vert.index] = 1.0 155 156 """ 157 # 頂点カラーで選択状態を確認 158 preview_vertex_color = me.vertex_colors.new() 159 for loop in me.loops: 160 v = vert_selection_values[loop.vertex_index] 161 if v != None: 162 preview_vertex_color.data[loop.index].color = (v, v, v) 163 else: 164 preview_vertex_color.data[loop.index].color = (0, 0, 0) 165 """ 166 167 kd = mathutils.kdtree.KDTree(len(me.vertices)) 168 # [kd.insert(v.co, v.index) for v in me.vertices] 169 for v in me.vertices: 170 kd.insert(v.co, v.index) 171 kd.balance() 172 173 blur_range = average_edge_length * self.blur_range_multi 174 175 for i in range(self.blur_count): 176 177 pre_vert_weights = [[0.0 for vg in ob.vertex_groups] for v in me.vertices] 178 for vert in me.vertices: 179 for vge in vert.groups: 180 pre_vert_weights[vert.index][vge.group] = vge.weight 181 182 for vert in me.vertices: 183 selection_value = vert_selection_values[vert.index] 184 if selection_value is None: 185 continue 186 187 near_infos = [] 188 total_effect = 0.0 189 for co, index, dist in kd.find_range(vert.co, blur_range): 190 ec = EmptyClass() 191 ec.index = index 192 if 0 < blur_range: 193 raw_effect = 1.0 - (dist / blur_range) 194 if self.smooth_method == 'TRIGONOMETRIC': 195 ec.effect = common.trigonometric_smooth(raw_effect) 196 else: 197 ec.effect = raw_effect 198 else: 199 ec.effect = 1.0 200 total_effect += ec.effect 201 near_infos.append(ec) 202 203 new_vert_weight = [0.0 for vg in ob.vertex_groups] 204 for ec in near_infos: 205 pre_vert_weight = pre_vert_weights[ec.index] 206 weight_multi = ec.effect / total_effect 207 for vg_index, near_vert_pre_weight_value in enumerate(pre_vert_weight): 208 current_vert_pre_weight_value = pre_vert_weights[vert.index][vg_index] 209 210 if self.blur_mode == 'NORMAL': 211 send_weight_value = near_vert_pre_weight_value 212 elif self.blur_mode == 'ADD': 213 if current_vert_pre_weight_value < near_vert_pre_weight_value: 214 send_weight_value = near_vert_pre_weight_value 215 else: 216 send_weight_value = current_vert_pre_weight_value 217 elif self.blur_mode == 'SUB': 218 if near_vert_pre_weight_value < current_vert_pre_weight_value: 219 send_weight_value = near_vert_pre_weight_value 220 else: 221 send_weight_value = current_vert_pre_weight_value 222 223 new_vert_weight[vg_index] += send_weight_value * weight_multi 224 225 for vg in ob.vertex_groups: 226 if self.target_vertex_group == 'ACTIVE' and ob.vertex_groups.active.name != vg.name: continue 227 if vg.lock_weight: 228 continue 229 230 pre_weight = pre_vert_weights[vert.index][vg.index] 231 new_weight = new_vert_weight[vg.index] 232 result_weight = (pre_weight * (1.0 - selection_value)) + (new_weight * selection_value) 233 234 if 0.0 < result_weight: 235 vg.add([vert.index], result_weight, 'REPLACE') 236 else: 237 vg.remove([vert.index]) 238 239 if self.is_vertex_group_limit_total: 240 bpy.ops.object.vertex_group_limit_total(group_select_mode='ALL', limit=4) 241 242 bpy.ops.object.mode_set(mode=pre_mode) 243 for selected_object in pre_selected_objects: 244 compat.set_select(selected_object, True) 245 return {'FINISHED'} 246 247 248@compat.BlRegister() 249class CNV_OT_selected_mesh_vertex_group_calculation(bpy.types.Operator): 250 bl_idname = 'mesh.selected_mesh_vertex_group_calculation' 251 bl_label = "選択部の頂点グループに四則演算" 252 bl_description = "選択メッシュの頂点グループの割り当てに四則演算を施します" 253 bl_options = {'REGISTER', 'UNDO'} 254 255 items = [ 256 ('LINER', "リニア", "", 'LINCURVE', 1), 257 ('TRIGONOMETRIC', "スムーズ", "", 'SMOOTHCURVE', 2), 258 ] 259 smooth_method = bpy.props.EnumProperty(items=items, name="減衰タイプ", default='TRIGONOMETRIC') 260 261 selection_blur_range_multi = bpy.props.FloatProperty(name="選択をぼかす範囲倍率", default=4.0, min=0.0, max=100.0, soft_min=0.0, soft_max=100.0, step=50, precision=1) 262 selection_blur_accuracy = bpy.props.IntProperty(name="選択をぼかす分割精度", default=3, min=0, max=10, soft_min=1, soft_max=10) 263 264 items = [ 265 ('ACTIVE', "アクティブのみ", "", 'LAYER_ACTIVE', 1), 266 ] 267 target_vertex_group = bpy.props.EnumProperty(items=items, name="対象頂点グループ", default='ACTIVE') 268 items = [ 269 ('ADD', "加算", "", 'ZOOMIN', 1), 270 ('SUB', "減算", "", 'ZOOMOUT', 2), 271 ('MULTI', "乗算", "", 'X', 3), 272 ('DIV', "除算", "", 'FULLSCREEN_EXIT', 4), 273 ] 274 calculation_mode = bpy.props.EnumProperty(items=items, name="四則演算モード", default='ADD') 275 calculation_value = bpy.props.FloatProperty(name="値", default=1.0, min=-100.0, max=100.0, soft_min=-100.0, soft_max=100.0, step=10, precision=1) 276 277 @classmethod 278 def poll(cls, context): 279 ob = context.active_object 280 if ob.type == 'MESH': 281 return len(ob.vertex_groups) > 0 282 return False 283 284 def draw(self, context): 285 self.layout.label(text="選択をぼかす", icon='UV_SYNC_SELECT') 286 self.layout.prop(self, 'smooth_method') 287 self.layout.prop(self, 'selection_blur_range_multi', text="範囲 | 辺の長さの平均×") 288 self.layout.prop(self, 'selection_blur_accuracy', text="精度 (分割数)") 289 290 self.layout.label(text="四則演算", icon='BRUSH_ADD') 291 self.layout.prop(self, 'target_vertex_group', text="対象グループ") 292 self.layout.prop(self, 'calculation_mode', text="モード") 293 self.layout.prop(self, 'calculation_value', text="値") 294 295 calculation_text = "式: 元のウェイト " 296 if self.calculation_mode == 'ADD': 297 calculation_text += "+" 298 elif self.calculation_mode == 'SUB': 299 calculation_text += "-" 300 elif self.calculation_mode == 'MULTI': 301 calculation_text += "×" 302 elif self.calculation_mode == 'DIV': 303 calculation_text += "÷" 304 calculation_text += " " + str(round(self.calculation_value, 1)) 305 self.layout.label(text=calculation_text) 306 307 def execute(self, context): 308 class EmptyClass: 309 pass 310 311 if self.calculation_mode == 'DIV' and self.calculation_value == 0.0: 312 self.report(type={'ERROR'}, message="0で除算することはできません、中止します") 313 return {'CANCELLED'} 314 315 ob = context.active_object 316 me = ob.data 317 318 pre_mode = ob.mode 319 bpy.ops.object.mode_set(mode='OBJECT') 320 321 pre_selected_objects = context.selected_objects[:] 322 for selected_object in pre_selected_objects: 323 compat.set_select(selected_object, False) 324 compat.set_select(ob, True) 325 326 bpy.ops.object.duplicate(linked=False, mode='TRANSLATION') 327 328 selection_ob = context.active_object 329 selection_me = selection_ob.data 330 331 for v in selection_me.vertices: 332 if v.hide: 333 v.hide = False 334 compat.set_select(v, False) 335 for e in selection_me.edges: 336 if e.hide: 337 e.hide = False 338 compat.set_select(e, False) 339 for p in selection_me.polygons: 340 if p.hide: 341 p.hide = False 342 compat.set_select(p, False) 343 344 bpy.ops.object.mode_set(mode='EDIT') 345 bpy.ops.mesh.select_all(action='INVERT') 346 if context.tool_settings.mesh_select_mode[0]: 347 bpy.ops.mesh.delete(type='VERT') 348 elif context.tool_settings.mesh_select_mode[1]: 349 bpy.ops.mesh.delete(type='EDGE') 350 elif context.tool_settings.mesh_select_mode[2]: 351 bpy.ops.mesh.delete(type='FACE') 352 bpy.ops.mesh.select_all(action='SELECT') 353 if 1 <= self.selection_blur_accuracy: 354 bpy.ops.mesh.subdivide(number_cuts=self.selection_blur_accuracy, smoothness=0, quadcorner='INNERVERT', fractal=0, fractal_along_normal=0, seed=0) 355 bpy.ops.object.mode_set(mode='OBJECT') 356 357 selection_kd = mathutils.kdtree.KDTree(len(selection_me.vertices)) 358 [selection_kd.insert(v.co, v.index) for v in selection_me.vertices] 359 selection_kd.balance() 360 common.remove_data([selection_ob, selection_me]) 361 362 compat.set_select(ob, True) 363 compat.set_active(context, ob) 364 365 bm = bmesh.new() 366 bm.from_mesh(me) 367 edge_lengths = [e.calc_length() for e in bm.edges] 368 bm.free() 369 edge_lengths.sort() 370 edge_lengths_center_index = int((len(edge_lengths) - 1) * 0.5) 371 average_edge_length = edge_lengths[edge_lengths_center_index] 372 selection_blur_range = average_edge_length * self.selection_blur_range_multi 373 374 vert_selection_values = [None for v in me.vertices] 375 for vert in me.vertices: 376 co, index, dist = selection_kd.find(vert.co) 377 if dist <= selection_blur_range + 0.00001: 378 if 0 < selection_blur_range: 379 if self.smooth_method == 'TRIGONOMETRIC': 380 value = common.trigonometric_smooth(1.0 - (dist / selection_blur_range)) 381 else: 382 value = 1.0 - (dist / selection_blur_range) 383 vert_selection_values[vert.index] = value 384 else: 385 vert_selection_values[vert.index] = 1.0 386 387 """ 388 # 頂点カラーで選択状態を確認 389 preview_vertex_color = me.vertex_colors.new() 390 for loop in me.loops: 391 v = vert_selection_values[loop.vertex_index] 392 if v != None: 393 preview_vertex_color.data[loop.index].color = (v, v, v) 394 else: 395 preview_vertex_color.data[loop.index].color = (0, 0, 0) 396 """ 397 398 for vert in me.vertices: 399 effect = vert_selection_values[vert.index] 400 if effect is None: 401 continue 402 403 pre_vert_weight = 0.0 404 for vge in vert.groups: 405 if ob.vertex_groups.active.index == vge.group: 406 pre_vert_weight = vge.weight 407 408 if self.calculation_mode == 'ADD': 409 new_vert_weight = pre_vert_weight + self.calculation_value 410 elif self.calculation_mode == 'SUB': 411 new_vert_weight = pre_vert_weight - self.calculation_value 412 elif self.calculation_mode == 'MULTI': 413 new_vert_weight = pre_vert_weight * self.calculation_value 414 elif self.calculation_mode == 'DIV': 415 new_vert_weight = pre_vert_weight / self.calculation_value 416 417 if new_vert_weight < 0.0: 418 new_vert_weight = 0.0 419 elif 1.0 < new_vert_weight: 420 new_vert_weight = 1.0 421 422 new_vert_weight = (pre_vert_weight * (1.0 - effect)) + (new_vert_weight * effect) 423 424 if 0.0 < new_vert_weight: 425 ob.vertex_groups.active.add([vert.index], new_vert_weight, 'REPLACE') 426 else: 427 ob.vertex_groups.active.remove([vert.index]) 428 429 bpy.ops.object.mode_set(mode=pre_mode) 430 for selected_object in pre_selected_objects: 431 compat.set_select(selected_object, True) 432 return {'FINISHED'}
@compat.BlRegister()
class
CNV_OT_selected_mesh_vertex_group_blur20@compat.BlRegister() 21class CNV_OT_selected_mesh_vertex_group_blur(bpy.types.Operator): 22 bl_idname = 'mesh.selected_mesh_vertex_group_blur' 23 bl_label = "選択部の頂点グループをぼかす" 24 bl_description = "選択メッシュの頂点グループの割り当てをぼかします" 25 bl_options = {'REGISTER', 'UNDO'} 26 27 items = [ 28 ('LINER', "リニア", "", 'LINCURVE', 1), 29 ('TRIGONOMETRIC', "スムーズ", "", 'SMOOTHCURVE', 2), 30 ] 31 smooth_method = bpy.props.EnumProperty(items=items, name="減衰タイプ", default='TRIGONOMETRIC') 32 33 selection_blur_range_multi = bpy.props.FloatProperty(name="選択をぼかす範囲倍率", default=4.0, min=0.0, max=100.0, soft_min=0.0, soft_max=100.0, step=50, precision=1) 34 selection_blur_accuracy = bpy.props.IntProperty(name="選択をぼかす分割精度", default=3, min=0, max=10, soft_min=1, soft_max=10) 35 36 items = [ 37 ('ALL', "全て", "", 'COLLAPSEMENU', 1), 38 ('ACTIVE', "アクティブのみ", "", 'LAYER_ACTIVE', 2), 39 ] 40 target_vertex_group = bpy.props.EnumProperty(items=items, name="対象頂点グループ", default='ALL') 41 items = [ 42 ('NORMAL', "通常・ぼかし", "", 'BRUSH_BLUR', 1), 43 ('ADD', "増加・拡張", "", 'BRUSH_DARKEN', 2), 44 ('SUB', "減少・縮小", "", 'BRUSH_LIGHTEN', 3), 45 ] 46 blur_mode = bpy.props.EnumProperty(items=items, name="ぼかしモード", default='NORMAL') 47 blur_range_multi = bpy.props.FloatProperty(name="ウェイトをぼかす範囲倍率", default=4.0, min=0.0, max=100.0, soft_min=0.0, soft_max=100.0, step=50, precision=1) 48 blur_count = bpy.props.IntProperty(name="ウェイトをぼかす回数", default=1, min=1, max=100, soft_min=1, soft_max=100) 49 is_vertex_group_limit_total = bpy.props.BoolProperty(name="ウェイト数を4つに制限", default=True) 50 51 @classmethod 52 def poll(cls, context): 53 ob = context.active_object 54 if ob.type == 'MESH': 55 if len(ob.vertex_groups): 56 return len(ob.data.vertices) and len(ob.data.edges) 57 return False 58 59 def invoke(self, context, event): 60 return context.window_manager.invoke_props_dialog(self) 61 62 def draw(self, context): 63 self.layout.prop(self, 'smooth_method') 64 65 self.layout.label(text="選択をぼかす", icon='UV_SYNC_SELECT') 66 self.layout.prop(self, 'selection_blur_range_multi', text="範囲 | 辺の長さの平均×") 67 self.layout.prop(self, 'selection_blur_accuracy', text="精度 (分割数)") 68 69 self.layout.label(text="頂点グループをぼかす", icon='GROUP_VERTEX') 70 self.layout.prop(self, 'target_vertex_group', text="対象グループ") 71 self.layout.prop(self, 'blur_mode', text="モード") 72 self.layout.prop(self, 'blur_range_multi', text="範囲 | 辺の長さの平均×") 73 self.layout.prop(self, 'blur_count', text="実行回数") 74 self.layout.prop(self, 'is_vertex_group_limit_total', icon='IMGDISPLAY') 75 76 def execute(self, context): 77 class EmptyClass: 78 pass 79 80 ob = context.active_object 81 me = ob.data 82 83 pre_mode = ob.mode 84 bpy.ops.object.mode_set(mode='OBJECT') 85 86 pre_selected_objects = context.selected_objects[:] 87 for selected_object in pre_selected_objects: 88 compat.set_select(selected_object, False) 89 compat.set_select(ob, True) 90 91 bpy.ops.object.duplicate(linked=False, mode='TRANSLATION') 92 93 selection_ob = context.active_object 94 selection_me = selection_ob.data 95 96 for v in selection_me.vertices: 97 if v.hide: 98 v.hide = False 99 compat.set_select(v, False) 100 for e in selection_me.edges: 101 if e.hide: 102 e.hide = False 103 compat.set_select(e, False) 104 for p in selection_me.polygons: 105 if p.hide: 106 p.hide = False 107 compat.set_select(p, False) 108 109 bpy.ops.object.mode_set(mode='EDIT') 110 bpy.ops.mesh.select_all(action='INVERT') 111 if context.tool_settings.mesh_select_mode[0]: 112 bpy.ops.mesh.delete(type='VERT') 113 elif context.tool_settings.mesh_select_mode[1]: 114 bpy.ops.mesh.delete(type='EDGE') 115 elif context.tool_settings.mesh_select_mode[2]: 116 bpy.ops.mesh.delete(type='FACE') 117 bpy.ops.mesh.select_all(action='SELECT') 118 if 1 <= self.selection_blur_accuracy: 119 # quadtriはデフォルトでFalseのため、省略(2.8では代わりにngon=Trueが追加) 120 bpy.ops.mesh.subdivide( 121 number_cuts=self.selection_blur_accuracy, 122 smoothness=0, quadcorner='INNERVERT', 123 fractal=0, fractal_along_normal=0, seed=0) 124 bpy.ops.object.mode_set(mode='OBJECT') 125 126 selection_kd = mathutils.kdtree.KDTree(len(selection_me.vertices)) 127 for v in selection_me.vertices: 128 selection_kd.insert(v.co, v.index) 129 selection_kd.balance() 130 common.remove_data([selection_ob, selection_me]) 131 132 compat.set_select(ob, True) 133 compat.set_active(context, ob) 134 135 bm = bmesh.new() 136 bm.from_mesh(me) 137 edge_lengths = [e.calc_length() for e in bm.edges] 138 bm.free() 139 edge_lengths.sort() 140 edge_lengths_center_index = int((len(edge_lengths) - 1) * 0.5) 141 average_edge_length = edge_lengths[edge_lengths_center_index] 142 selection_blur_range = average_edge_length * self.selection_blur_range_multi 143 144 vert_selection_values = [None for v in me.vertices] 145 for vert in me.vertices: 146 co, index, dist = selection_kd.find(vert.co) 147 if dist <= selection_blur_range + 0.00001: 148 if 0 < selection_blur_range: 149 if self.smooth_method == 'TRIGONOMETRIC': 150 value = common.trigonometric_smooth(1.0 - (dist / selection_blur_range)) 151 else: 152 value = 1.0 - (dist / selection_blur_range) 153 vert_selection_values[vert.index] = value 154 else: 155 vert_selection_values[vert.index] = 1.0 156 157 """ 158 # 頂点カラーで選択状態を確認 159 preview_vertex_color = me.vertex_colors.new() 160 for loop in me.loops: 161 v = vert_selection_values[loop.vertex_index] 162 if v != None: 163 preview_vertex_color.data[loop.index].color = (v, v, v) 164 else: 165 preview_vertex_color.data[loop.index].color = (0, 0, 0) 166 """ 167 168 kd = mathutils.kdtree.KDTree(len(me.vertices)) 169 # [kd.insert(v.co, v.index) for v in me.vertices] 170 for v in me.vertices: 171 kd.insert(v.co, v.index) 172 kd.balance() 173 174 blur_range = average_edge_length * self.blur_range_multi 175 176 for i in range(self.blur_count): 177 178 pre_vert_weights = [[0.0 for vg in ob.vertex_groups] for v in me.vertices] 179 for vert in me.vertices: 180 for vge in vert.groups: 181 pre_vert_weights[vert.index][vge.group] = vge.weight 182 183 for vert in me.vertices: 184 selection_value = vert_selection_values[vert.index] 185 if selection_value is None: 186 continue 187 188 near_infos = [] 189 total_effect = 0.0 190 for co, index, dist in kd.find_range(vert.co, blur_range): 191 ec = EmptyClass() 192 ec.index = index 193 if 0 < blur_range: 194 raw_effect = 1.0 - (dist / blur_range) 195 if self.smooth_method == 'TRIGONOMETRIC': 196 ec.effect = common.trigonometric_smooth(raw_effect) 197 else: 198 ec.effect = raw_effect 199 else: 200 ec.effect = 1.0 201 total_effect += ec.effect 202 near_infos.append(ec) 203 204 new_vert_weight = [0.0 for vg in ob.vertex_groups] 205 for ec in near_infos: 206 pre_vert_weight = pre_vert_weights[ec.index] 207 weight_multi = ec.effect / total_effect 208 for vg_index, near_vert_pre_weight_value in enumerate(pre_vert_weight): 209 current_vert_pre_weight_value = pre_vert_weights[vert.index][vg_index] 210 211 if self.blur_mode == 'NORMAL': 212 send_weight_value = near_vert_pre_weight_value 213 elif self.blur_mode == 'ADD': 214 if current_vert_pre_weight_value < near_vert_pre_weight_value: 215 send_weight_value = near_vert_pre_weight_value 216 else: 217 send_weight_value = current_vert_pre_weight_value 218 elif self.blur_mode == 'SUB': 219 if near_vert_pre_weight_value < current_vert_pre_weight_value: 220 send_weight_value = near_vert_pre_weight_value 221 else: 222 send_weight_value = current_vert_pre_weight_value 223 224 new_vert_weight[vg_index] += send_weight_value * weight_multi 225 226 for vg in ob.vertex_groups: 227 if self.target_vertex_group == 'ACTIVE' and ob.vertex_groups.active.name != vg.name: continue 228 if vg.lock_weight: 229 continue 230 231 pre_weight = pre_vert_weights[vert.index][vg.index] 232 new_weight = new_vert_weight[vg.index] 233 result_weight = (pre_weight * (1.0 - selection_value)) + (new_weight * selection_value) 234 235 if 0.0 < result_weight: 236 vg.add([vert.index], result_weight, 'REPLACE') 237 else: 238 vg.remove([vert.index]) 239 240 if self.is_vertex_group_limit_total: 241 bpy.ops.object.vertex_group_limit_total(group_select_mode='ALL', limit=4) 242 243 bpy.ops.object.mode_set(mode=pre_mode) 244 for selected_object in pre_selected_objects: 245 compat.set_select(selected_object, True) 246 return {'FINISHED'}
items =
[('NORMAL', '通常・ぼかし', '', 'BRUSH_BLUR', 1), ('ADD', '増加・拡張', '', 'BRUSH_DARKEN', 2), ('SUB', '減少・縮小', '', 'BRUSH_LIGHTEN', 3)]
smooth_method: <_PropertyDeferred, <built-in function EnumProperty>, {'items': [('LINER', 'リニア', '', 'LINCURVE', 1), ('TRIGONOMETRIC', 'スムーズ', '', 'SMOOTHCURVE', 2)], 'name': '減衰タイプ', 'default': 'TRIGONOMETRIC', 'attr': 'smooth_method'}> =
<_PropertyDeferred, <built-in function EnumProperty>, {'items': [('LINER', 'リニア', '', 'LINCURVE', 1), ('TRIGONOMETRIC', 'スムーズ', '', 'SMOOTHCURVE', 2)], 'name': '減衰タイプ', 'default': 'TRIGONOMETRIC', 'attr': 'smooth_method'}>
selection_blur_range_multi: <_PropertyDeferred, <built-in function FloatProperty>, {'name': '選択をぼかす範囲倍率', 'default': 4.0, 'min': 0.0, 'max': 100.0, 'soft_min': 0.0, 'soft_max': 100.0, 'step': 50, 'precision': 1, 'attr': 'selection_blur_range_multi'}> =
<_PropertyDeferred, <built-in function FloatProperty>, {'name': '選択をぼかす範囲倍率', 'default': 4.0, 'min': 0.0, 'max': 100.0, 'soft_min': 0.0, 'soft_max': 100.0, 'step': 50, 'precision': 1, 'attr': 'selection_blur_range_multi'}>
selection_blur_accuracy: <_PropertyDeferred, <built-in function IntProperty>, {'name': '選択をぼかす分割精度', 'default': 3, 'min': 0, 'max': 10, 'soft_min': 1, 'soft_max': 10, 'attr': 'selection_blur_accuracy'}> =
<_PropertyDeferred, <built-in function IntProperty>, {'name': '選択をぼかす分割精度', 'default': 3, 'min': 0, 'max': 10, 'soft_min': 1, 'soft_max': 10, 'attr': 'selection_blur_accuracy'}>
target_vertex_group: <_PropertyDeferred, <built-in function EnumProperty>, {'items': [('ALL', '全て', '', 'COLLAPSEMENU', 1), ('ACTIVE', 'アクティブのみ', '', 'LAYER_ACTIVE', 2)], 'name': '対象頂点グループ', 'default': 'ALL', 'attr': 'target_vertex_group'}> =
<_PropertyDeferred, <built-in function EnumProperty>, {'items': [('ALL', '全て', '', 'COLLAPSEMENU', 1), ('ACTIVE', 'アクティブのみ', '', 'LAYER_ACTIVE', 2)], 'name': '対象頂点グループ', 'default': 'ALL', 'attr': 'target_vertex_group'}>
blur_mode: <_PropertyDeferred, <built-in function EnumProperty>, {'items': [('NORMAL', '通常・ぼかし', '', 'BRUSH_BLUR', 1), ('ADD', '増加・拡張', '', 'BRUSH_DARKEN', 2), ('SUB', '減少・縮小', '', 'BRUSH_LIGHTEN', 3)], 'name': 'ぼかしモード', 'default': 'NORMAL', 'attr': 'blur_mode'}> =
<_PropertyDeferred, <built-in function EnumProperty>, {'items': [('NORMAL', '通常・ぼかし', '', 'BRUSH_BLUR', 1), ('ADD', '増加・拡張', '', 'BRUSH_DARKEN', 2), ('SUB', '減少・縮小', '', 'BRUSH_LIGHTEN', 3)], 'name': 'ぼかしモード', 'default': 'NORMAL', 'attr': 'blur_mode'}>
blur_range_multi: <_PropertyDeferred, <built-in function FloatProperty>, {'name': 'ウェイトをぼかす範囲倍率', 'default': 4.0, 'min': 0.0, 'max': 100.0, 'soft_min': 0.0, 'soft_max': 100.0, 'step': 50, 'precision': 1, 'attr': 'blur_range_multi'}> =
<_PropertyDeferred, <built-in function FloatProperty>, {'name': 'ウェイトをぼかす範囲倍率', 'default': 4.0, 'min': 0.0, 'max': 100.0, 'soft_min': 0.0, 'soft_max': 100.0, 'step': 50, 'precision': 1, 'attr': 'blur_range_multi'}>
blur_count: <_PropertyDeferred, <built-in function IntProperty>, {'name': 'ウェイトをぼかす回数', 'default': 1, 'min': 1, 'max': 100, 'soft_min': 1, 'soft_max': 100, 'attr': 'blur_count'}> =
<_PropertyDeferred, <built-in function IntProperty>, {'name': 'ウェイトをぼかす回数', 'default': 1, 'min': 1, 'max': 100, 'soft_min': 1, 'soft_max': 100, 'attr': 'blur_count'}>
is_vertex_group_limit_total: <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'ウェイト数を4つに制限', 'default': True, 'attr': 'is_vertex_group_limit_total'}> =
<_PropertyDeferred, <built-in function BoolProperty>, {'name': 'ウェイト数を4つに制限', 'default': True, 'attr': 'is_vertex_group_limit_total'}>
def
draw(self, context):
62 def draw(self, context): 63 self.layout.prop(self, 'smooth_method') 64 65 self.layout.label(text="選択をぼかす", icon='UV_SYNC_SELECT') 66 self.layout.prop(self, 'selection_blur_range_multi', text="範囲 | 辺の長さの平均×") 67 self.layout.prop(self, 'selection_blur_accuracy', text="精度 (分割数)") 68 69 self.layout.label(text="頂点グループをぼかす", icon='GROUP_VERTEX') 70 self.layout.prop(self, 'target_vertex_group', text="対象グループ") 71 self.layout.prop(self, 'blur_mode', text="モード") 72 self.layout.prop(self, 'blur_range_multi', text="範囲 | 辺の長さの平均×") 73 self.layout.prop(self, 'blur_count', text="実行回数") 74 self.layout.prop(self, 'is_vertex_group_limit_total', icon='IMGDISPLAY')
def
execute(self, context):
76 def execute(self, context): 77 class EmptyClass: 78 pass 79 80 ob = context.active_object 81 me = ob.data 82 83 pre_mode = ob.mode 84 bpy.ops.object.mode_set(mode='OBJECT') 85 86 pre_selected_objects = context.selected_objects[:] 87 for selected_object in pre_selected_objects: 88 compat.set_select(selected_object, False) 89 compat.set_select(ob, True) 90 91 bpy.ops.object.duplicate(linked=False, mode='TRANSLATION') 92 93 selection_ob = context.active_object 94 selection_me = selection_ob.data 95 96 for v in selection_me.vertices: 97 if v.hide: 98 v.hide = False 99 compat.set_select(v, False) 100 for e in selection_me.edges: 101 if e.hide: 102 e.hide = False 103 compat.set_select(e, False) 104 for p in selection_me.polygons: 105 if p.hide: 106 p.hide = False 107 compat.set_select(p, False) 108 109 bpy.ops.object.mode_set(mode='EDIT') 110 bpy.ops.mesh.select_all(action='INVERT') 111 if context.tool_settings.mesh_select_mode[0]: 112 bpy.ops.mesh.delete(type='VERT') 113 elif context.tool_settings.mesh_select_mode[1]: 114 bpy.ops.mesh.delete(type='EDGE') 115 elif context.tool_settings.mesh_select_mode[2]: 116 bpy.ops.mesh.delete(type='FACE') 117 bpy.ops.mesh.select_all(action='SELECT') 118 if 1 <= self.selection_blur_accuracy: 119 # quadtriはデフォルトでFalseのため、省略(2.8では代わりにngon=Trueが追加) 120 bpy.ops.mesh.subdivide( 121 number_cuts=self.selection_blur_accuracy, 122 smoothness=0, quadcorner='INNERVERT', 123 fractal=0, fractal_along_normal=0, seed=0) 124 bpy.ops.object.mode_set(mode='OBJECT') 125 126 selection_kd = mathutils.kdtree.KDTree(len(selection_me.vertices)) 127 for v in selection_me.vertices: 128 selection_kd.insert(v.co, v.index) 129 selection_kd.balance() 130 common.remove_data([selection_ob, selection_me]) 131 132 compat.set_select(ob, True) 133 compat.set_active(context, ob) 134 135 bm = bmesh.new() 136 bm.from_mesh(me) 137 edge_lengths = [e.calc_length() for e in bm.edges] 138 bm.free() 139 edge_lengths.sort() 140 edge_lengths_center_index = int((len(edge_lengths) - 1) * 0.5) 141 average_edge_length = edge_lengths[edge_lengths_center_index] 142 selection_blur_range = average_edge_length * self.selection_blur_range_multi 143 144 vert_selection_values = [None for v in me.vertices] 145 for vert in me.vertices: 146 co, index, dist = selection_kd.find(vert.co) 147 if dist <= selection_blur_range + 0.00001: 148 if 0 < selection_blur_range: 149 if self.smooth_method == 'TRIGONOMETRIC': 150 value = common.trigonometric_smooth(1.0 - (dist / selection_blur_range)) 151 else: 152 value = 1.0 - (dist / selection_blur_range) 153 vert_selection_values[vert.index] = value 154 else: 155 vert_selection_values[vert.index] = 1.0 156 157 """ 158 # 頂点カラーで選択状態を確認 159 preview_vertex_color = me.vertex_colors.new() 160 for loop in me.loops: 161 v = vert_selection_values[loop.vertex_index] 162 if v != None: 163 preview_vertex_color.data[loop.index].color = (v, v, v) 164 else: 165 preview_vertex_color.data[loop.index].color = (0, 0, 0) 166 """ 167 168 kd = mathutils.kdtree.KDTree(len(me.vertices)) 169 # [kd.insert(v.co, v.index) for v in me.vertices] 170 for v in me.vertices: 171 kd.insert(v.co, v.index) 172 kd.balance() 173 174 blur_range = average_edge_length * self.blur_range_multi 175 176 for i in range(self.blur_count): 177 178 pre_vert_weights = [[0.0 for vg in ob.vertex_groups] for v in me.vertices] 179 for vert in me.vertices: 180 for vge in vert.groups: 181 pre_vert_weights[vert.index][vge.group] = vge.weight 182 183 for vert in me.vertices: 184 selection_value = vert_selection_values[vert.index] 185 if selection_value is None: 186 continue 187 188 near_infos = [] 189 total_effect = 0.0 190 for co, index, dist in kd.find_range(vert.co, blur_range): 191 ec = EmptyClass() 192 ec.index = index 193 if 0 < blur_range: 194 raw_effect = 1.0 - (dist / blur_range) 195 if self.smooth_method == 'TRIGONOMETRIC': 196 ec.effect = common.trigonometric_smooth(raw_effect) 197 else: 198 ec.effect = raw_effect 199 else: 200 ec.effect = 1.0 201 total_effect += ec.effect 202 near_infos.append(ec) 203 204 new_vert_weight = [0.0 for vg in ob.vertex_groups] 205 for ec in near_infos: 206 pre_vert_weight = pre_vert_weights[ec.index] 207 weight_multi = ec.effect / total_effect 208 for vg_index, near_vert_pre_weight_value in enumerate(pre_vert_weight): 209 current_vert_pre_weight_value = pre_vert_weights[vert.index][vg_index] 210 211 if self.blur_mode == 'NORMAL': 212 send_weight_value = near_vert_pre_weight_value 213 elif self.blur_mode == 'ADD': 214 if current_vert_pre_weight_value < near_vert_pre_weight_value: 215 send_weight_value = near_vert_pre_weight_value 216 else: 217 send_weight_value = current_vert_pre_weight_value 218 elif self.blur_mode == 'SUB': 219 if near_vert_pre_weight_value < current_vert_pre_weight_value: 220 send_weight_value = near_vert_pre_weight_value 221 else: 222 send_weight_value = current_vert_pre_weight_value 223 224 new_vert_weight[vg_index] += send_weight_value * weight_multi 225 226 for vg in ob.vertex_groups: 227 if self.target_vertex_group == 'ACTIVE' and ob.vertex_groups.active.name != vg.name: continue 228 if vg.lock_weight: 229 continue 230 231 pre_weight = pre_vert_weights[vert.index][vg.index] 232 new_weight = new_vert_weight[vg.index] 233 result_weight = (pre_weight * (1.0 - selection_value)) + (new_weight * selection_value) 234 235 if 0.0 < result_weight: 236 vg.add([vert.index], result_weight, 'REPLACE') 237 else: 238 vg.remove([vert.index]) 239 240 if self.is_vertex_group_limit_total: 241 bpy.ops.object.vertex_group_limit_total(group_select_mode='ALL', limit=4) 242 243 bpy.ops.object.mode_set(mode=pre_mode) 244 for selected_object in pre_selected_objects: 245 compat.set_select(selected_object, True) 246 return {'FINISHED'}
Inherited Members
- bpy_types.Operator
- as_keywords
- poll_message_set
- builtins.bpy_struct
- keys
- values
- get
- pop
- as_pointer
- keyframe_insert
- keyframe_delete
- driver_add
- driver_remove
- is_property_set
- property_unset
- is_property_readonly
- is_property_overridable_library
- property_overridable_library_set
- path_resolve
- path_from_id
- type_recast
- bl_rna_get_subclass_py
- bl_rna_get_subclass
- id_properties_ensure
- id_properties_clear
- id_properties_ui
- id_data
@compat.BlRegister()
class
CNV_OT_selected_mesh_vertex_group_calculation249@compat.BlRegister() 250class CNV_OT_selected_mesh_vertex_group_calculation(bpy.types.Operator): 251 bl_idname = 'mesh.selected_mesh_vertex_group_calculation' 252 bl_label = "選択部の頂点グループに四則演算" 253 bl_description = "選択メッシュの頂点グループの割り当てに四則演算を施します" 254 bl_options = {'REGISTER', 'UNDO'} 255 256 items = [ 257 ('LINER', "リニア", "", 'LINCURVE', 1), 258 ('TRIGONOMETRIC', "スムーズ", "", 'SMOOTHCURVE', 2), 259 ] 260 smooth_method = bpy.props.EnumProperty(items=items, name="減衰タイプ", default='TRIGONOMETRIC') 261 262 selection_blur_range_multi = bpy.props.FloatProperty(name="選択をぼかす範囲倍率", default=4.0, min=0.0, max=100.0, soft_min=0.0, soft_max=100.0, step=50, precision=1) 263 selection_blur_accuracy = bpy.props.IntProperty(name="選択をぼかす分割精度", default=3, min=0, max=10, soft_min=1, soft_max=10) 264 265 items = [ 266 ('ACTIVE', "アクティブのみ", "", 'LAYER_ACTIVE', 1), 267 ] 268 target_vertex_group = bpy.props.EnumProperty(items=items, name="対象頂点グループ", default='ACTIVE') 269 items = [ 270 ('ADD', "加算", "", 'ZOOMIN', 1), 271 ('SUB', "減算", "", 'ZOOMOUT', 2), 272 ('MULTI', "乗算", "", 'X', 3), 273 ('DIV', "除算", "", 'FULLSCREEN_EXIT', 4), 274 ] 275 calculation_mode = bpy.props.EnumProperty(items=items, name="四則演算モード", default='ADD') 276 calculation_value = bpy.props.FloatProperty(name="値", default=1.0, min=-100.0, max=100.0, soft_min=-100.0, soft_max=100.0, step=10, precision=1) 277 278 @classmethod 279 def poll(cls, context): 280 ob = context.active_object 281 if ob.type == 'MESH': 282 return len(ob.vertex_groups) > 0 283 return False 284 285 def draw(self, context): 286 self.layout.label(text="選択をぼかす", icon='UV_SYNC_SELECT') 287 self.layout.prop(self, 'smooth_method') 288 self.layout.prop(self, 'selection_blur_range_multi', text="範囲 | 辺の長さの平均×") 289 self.layout.prop(self, 'selection_blur_accuracy', text="精度 (分割数)") 290 291 self.layout.label(text="四則演算", icon='BRUSH_ADD') 292 self.layout.prop(self, 'target_vertex_group', text="対象グループ") 293 self.layout.prop(self, 'calculation_mode', text="モード") 294 self.layout.prop(self, 'calculation_value', text="値") 295 296 calculation_text = "式: 元のウェイト " 297 if self.calculation_mode == 'ADD': 298 calculation_text += "+" 299 elif self.calculation_mode == 'SUB': 300 calculation_text += "-" 301 elif self.calculation_mode == 'MULTI': 302 calculation_text += "×" 303 elif self.calculation_mode == 'DIV': 304 calculation_text += "÷" 305 calculation_text += " " + str(round(self.calculation_value, 1)) 306 self.layout.label(text=calculation_text) 307 308 def execute(self, context): 309 class EmptyClass: 310 pass 311 312 if self.calculation_mode == 'DIV' and self.calculation_value == 0.0: 313 self.report(type={'ERROR'}, message="0で除算することはできません、中止します") 314 return {'CANCELLED'} 315 316 ob = context.active_object 317 me = ob.data 318 319 pre_mode = ob.mode 320 bpy.ops.object.mode_set(mode='OBJECT') 321 322 pre_selected_objects = context.selected_objects[:] 323 for selected_object in pre_selected_objects: 324 compat.set_select(selected_object, False) 325 compat.set_select(ob, True) 326 327 bpy.ops.object.duplicate(linked=False, mode='TRANSLATION') 328 329 selection_ob = context.active_object 330 selection_me = selection_ob.data 331 332 for v in selection_me.vertices: 333 if v.hide: 334 v.hide = False 335 compat.set_select(v, False) 336 for e in selection_me.edges: 337 if e.hide: 338 e.hide = False 339 compat.set_select(e, False) 340 for p in selection_me.polygons: 341 if p.hide: 342 p.hide = False 343 compat.set_select(p, False) 344 345 bpy.ops.object.mode_set(mode='EDIT') 346 bpy.ops.mesh.select_all(action='INVERT') 347 if context.tool_settings.mesh_select_mode[0]: 348 bpy.ops.mesh.delete(type='VERT') 349 elif context.tool_settings.mesh_select_mode[1]: 350 bpy.ops.mesh.delete(type='EDGE') 351 elif context.tool_settings.mesh_select_mode[2]: 352 bpy.ops.mesh.delete(type='FACE') 353 bpy.ops.mesh.select_all(action='SELECT') 354 if 1 <= self.selection_blur_accuracy: 355 bpy.ops.mesh.subdivide(number_cuts=self.selection_blur_accuracy, smoothness=0, quadcorner='INNERVERT', fractal=0, fractal_along_normal=0, seed=0) 356 bpy.ops.object.mode_set(mode='OBJECT') 357 358 selection_kd = mathutils.kdtree.KDTree(len(selection_me.vertices)) 359 [selection_kd.insert(v.co, v.index) for v in selection_me.vertices] 360 selection_kd.balance() 361 common.remove_data([selection_ob, selection_me]) 362 363 compat.set_select(ob, True) 364 compat.set_active(context, ob) 365 366 bm = bmesh.new() 367 bm.from_mesh(me) 368 edge_lengths = [e.calc_length() for e in bm.edges] 369 bm.free() 370 edge_lengths.sort() 371 edge_lengths_center_index = int((len(edge_lengths) - 1) * 0.5) 372 average_edge_length = edge_lengths[edge_lengths_center_index] 373 selection_blur_range = average_edge_length * self.selection_blur_range_multi 374 375 vert_selection_values = [None for v in me.vertices] 376 for vert in me.vertices: 377 co, index, dist = selection_kd.find(vert.co) 378 if dist <= selection_blur_range + 0.00001: 379 if 0 < selection_blur_range: 380 if self.smooth_method == 'TRIGONOMETRIC': 381 value = common.trigonometric_smooth(1.0 - (dist / selection_blur_range)) 382 else: 383 value = 1.0 - (dist / selection_blur_range) 384 vert_selection_values[vert.index] = value 385 else: 386 vert_selection_values[vert.index] = 1.0 387 388 """ 389 # 頂点カラーで選択状態を確認 390 preview_vertex_color = me.vertex_colors.new() 391 for loop in me.loops: 392 v = vert_selection_values[loop.vertex_index] 393 if v != None: 394 preview_vertex_color.data[loop.index].color = (v, v, v) 395 else: 396 preview_vertex_color.data[loop.index].color = (0, 0, 0) 397 """ 398 399 for vert in me.vertices: 400 effect = vert_selection_values[vert.index] 401 if effect is None: 402 continue 403 404 pre_vert_weight = 0.0 405 for vge in vert.groups: 406 if ob.vertex_groups.active.index == vge.group: 407 pre_vert_weight = vge.weight 408 409 if self.calculation_mode == 'ADD': 410 new_vert_weight = pre_vert_weight + self.calculation_value 411 elif self.calculation_mode == 'SUB': 412 new_vert_weight = pre_vert_weight - self.calculation_value 413 elif self.calculation_mode == 'MULTI': 414 new_vert_weight = pre_vert_weight * self.calculation_value 415 elif self.calculation_mode == 'DIV': 416 new_vert_weight = pre_vert_weight / self.calculation_value 417 418 if new_vert_weight < 0.0: 419 new_vert_weight = 0.0 420 elif 1.0 < new_vert_weight: 421 new_vert_weight = 1.0 422 423 new_vert_weight = (pre_vert_weight * (1.0 - effect)) + (new_vert_weight * effect) 424 425 if 0.0 < new_vert_weight: 426 ob.vertex_groups.active.add([vert.index], new_vert_weight, 'REPLACE') 427 else: 428 ob.vertex_groups.active.remove([vert.index]) 429 430 bpy.ops.object.mode_set(mode=pre_mode) 431 for selected_object in pre_selected_objects: 432 compat.set_select(selected_object, True) 433 return {'FINISHED'}
items =
[('ADD', '加算', '', 'ZOOMIN', 1), ('SUB', '減算', '', 'ZOOMOUT', 2), ('MULTI', '乗算', '', 'X', 3), ('DIV', '除算', '', 'FULLSCREEN_EXIT', 4)]
smooth_method: <_PropertyDeferred, <built-in function EnumProperty>, {'items': [('LINER', 'リニア', '', 'LINCURVE', 1), ('TRIGONOMETRIC', 'スムーズ', '', 'SMOOTHCURVE', 2)], 'name': '減衰タイプ', 'default': 'TRIGONOMETRIC', 'attr': 'smooth_method'}> =
<_PropertyDeferred, <built-in function EnumProperty>, {'items': [('LINER', 'リニア', '', 'LINCURVE', 1), ('TRIGONOMETRIC', 'スムーズ', '', 'SMOOTHCURVE', 2)], 'name': '減衰タイプ', 'default': 'TRIGONOMETRIC', 'attr': 'smooth_method'}>
selection_blur_range_multi: <_PropertyDeferred, <built-in function FloatProperty>, {'name': '選択をぼかす範囲倍率', 'default': 4.0, 'min': 0.0, 'max': 100.0, 'soft_min': 0.0, 'soft_max': 100.0, 'step': 50, 'precision': 1, 'attr': 'selection_blur_range_multi'}> =
<_PropertyDeferred, <built-in function FloatProperty>, {'name': '選択をぼかす範囲倍率', 'default': 4.0, 'min': 0.0, 'max': 100.0, 'soft_min': 0.0, 'soft_max': 100.0, 'step': 50, 'precision': 1, 'attr': 'selection_blur_range_multi'}>
selection_blur_accuracy: <_PropertyDeferred, <built-in function IntProperty>, {'name': '選択をぼかす分割精度', 'default': 3, 'min': 0, 'max': 10, 'soft_min': 1, 'soft_max': 10, 'attr': 'selection_blur_accuracy'}> =
<_PropertyDeferred, <built-in function IntProperty>, {'name': '選択をぼかす分割精度', 'default': 3, 'min': 0, 'max': 10, 'soft_min': 1, 'soft_max': 10, 'attr': 'selection_blur_accuracy'}>
target_vertex_group: <_PropertyDeferred, <built-in function EnumProperty>, {'items': [('ACTIVE', 'アクティブのみ', '', 'LAYER_ACTIVE', 1)], 'name': '対象頂点グループ', 'default': 'ACTIVE', 'attr': 'target_vertex_group'}> =
<_PropertyDeferred, <built-in function EnumProperty>, {'items': [('ACTIVE', 'アクティブのみ', '', 'LAYER_ACTIVE', 1)], 'name': '対象頂点グループ', 'default': 'ACTIVE', 'attr': 'target_vertex_group'}>
calculation_mode: <_PropertyDeferred, <built-in function EnumProperty>, {'items': [('ADD', '加算', '', 'ZOOMIN', 1), ('SUB', '減算', '', 'ZOOMOUT', 2), ('MULTI', '乗算', '', 'X', 3), ('DIV', '除算', '', 'FULLSCREEN_EXIT', 4)], 'name': '四則演算モード', 'default': 'ADD', 'attr': 'calculation_mode'}> =
<_PropertyDeferred, <built-in function EnumProperty>, {'items': [('ADD', '加算', '', 'ZOOMIN', 1), ('SUB', '減算', '', 'ZOOMOUT', 2), ('MULTI', '乗算', '', 'X', 3), ('DIV', '除算', '', 'FULLSCREEN_EXIT', 4)], 'name': '四則演算モード', 'default': 'ADD', 'attr': 'calculation_mode'}>
calculation_value: <_PropertyDeferred, <built-in function FloatProperty>, {'name': '値', 'default': 1.0, 'min': -100.0, 'max': 100.0, 'soft_min': -100.0, 'soft_max': 100.0, 'step': 10, 'precision': 1, 'attr': 'calculation_value'}> =
<_PropertyDeferred, <built-in function FloatProperty>, {'name': '値', 'default': 1.0, 'min': -100.0, 'max': 100.0, 'soft_min': -100.0, 'soft_max': 100.0, 'step': 10, 'precision': 1, 'attr': 'calculation_value'}>
def
draw(self, context):
285 def draw(self, context): 286 self.layout.label(text="選択をぼかす", icon='UV_SYNC_SELECT') 287 self.layout.prop(self, 'smooth_method') 288 self.layout.prop(self, 'selection_blur_range_multi', text="範囲 | 辺の長さの平均×") 289 self.layout.prop(self, 'selection_blur_accuracy', text="精度 (分割数)") 290 291 self.layout.label(text="四則演算", icon='BRUSH_ADD') 292 self.layout.prop(self, 'target_vertex_group', text="対象グループ") 293 self.layout.prop(self, 'calculation_mode', text="モード") 294 self.layout.prop(self, 'calculation_value', text="値") 295 296 calculation_text = "式: 元のウェイト " 297 if self.calculation_mode == 'ADD': 298 calculation_text += "+" 299 elif self.calculation_mode == 'SUB': 300 calculation_text += "-" 301 elif self.calculation_mode == 'MULTI': 302 calculation_text += "×" 303 elif self.calculation_mode == 'DIV': 304 calculation_text += "÷" 305 calculation_text += " " + str(round(self.calculation_value, 1)) 306 self.layout.label(text=calculation_text)
def
execute(self, context):
308 def execute(self, context): 309 class EmptyClass: 310 pass 311 312 if self.calculation_mode == 'DIV' and self.calculation_value == 0.0: 313 self.report(type={'ERROR'}, message="0で除算することはできません、中止します") 314 return {'CANCELLED'} 315 316 ob = context.active_object 317 me = ob.data 318 319 pre_mode = ob.mode 320 bpy.ops.object.mode_set(mode='OBJECT') 321 322 pre_selected_objects = context.selected_objects[:] 323 for selected_object in pre_selected_objects: 324 compat.set_select(selected_object, False) 325 compat.set_select(ob, True) 326 327 bpy.ops.object.duplicate(linked=False, mode='TRANSLATION') 328 329 selection_ob = context.active_object 330 selection_me = selection_ob.data 331 332 for v in selection_me.vertices: 333 if v.hide: 334 v.hide = False 335 compat.set_select(v, False) 336 for e in selection_me.edges: 337 if e.hide: 338 e.hide = False 339 compat.set_select(e, False) 340 for p in selection_me.polygons: 341 if p.hide: 342 p.hide = False 343 compat.set_select(p, False) 344 345 bpy.ops.object.mode_set(mode='EDIT') 346 bpy.ops.mesh.select_all(action='INVERT') 347 if context.tool_settings.mesh_select_mode[0]: 348 bpy.ops.mesh.delete(type='VERT') 349 elif context.tool_settings.mesh_select_mode[1]: 350 bpy.ops.mesh.delete(type='EDGE') 351 elif context.tool_settings.mesh_select_mode[2]: 352 bpy.ops.mesh.delete(type='FACE') 353 bpy.ops.mesh.select_all(action='SELECT') 354 if 1 <= self.selection_blur_accuracy: 355 bpy.ops.mesh.subdivide(number_cuts=self.selection_blur_accuracy, smoothness=0, quadcorner='INNERVERT', fractal=0, fractal_along_normal=0, seed=0) 356 bpy.ops.object.mode_set(mode='OBJECT') 357 358 selection_kd = mathutils.kdtree.KDTree(len(selection_me.vertices)) 359 [selection_kd.insert(v.co, v.index) for v in selection_me.vertices] 360 selection_kd.balance() 361 common.remove_data([selection_ob, selection_me]) 362 363 compat.set_select(ob, True) 364 compat.set_active(context, ob) 365 366 bm = bmesh.new() 367 bm.from_mesh(me) 368 edge_lengths = [e.calc_length() for e in bm.edges] 369 bm.free() 370 edge_lengths.sort() 371 edge_lengths_center_index = int((len(edge_lengths) - 1) * 0.5) 372 average_edge_length = edge_lengths[edge_lengths_center_index] 373 selection_blur_range = average_edge_length * self.selection_blur_range_multi 374 375 vert_selection_values = [None for v in me.vertices] 376 for vert in me.vertices: 377 co, index, dist = selection_kd.find(vert.co) 378 if dist <= selection_blur_range + 0.00001: 379 if 0 < selection_blur_range: 380 if self.smooth_method == 'TRIGONOMETRIC': 381 value = common.trigonometric_smooth(1.0 - (dist / selection_blur_range)) 382 else: 383 value = 1.0 - (dist / selection_blur_range) 384 vert_selection_values[vert.index] = value 385 else: 386 vert_selection_values[vert.index] = 1.0 387 388 """ 389 # 頂点カラーで選択状態を確認 390 preview_vertex_color = me.vertex_colors.new() 391 for loop in me.loops: 392 v = vert_selection_values[loop.vertex_index] 393 if v != None: 394 preview_vertex_color.data[loop.index].color = (v, v, v) 395 else: 396 preview_vertex_color.data[loop.index].color = (0, 0, 0) 397 """ 398 399 for vert in me.vertices: 400 effect = vert_selection_values[vert.index] 401 if effect is None: 402 continue 403 404 pre_vert_weight = 0.0 405 for vge in vert.groups: 406 if ob.vertex_groups.active.index == vge.group: 407 pre_vert_weight = vge.weight 408 409 if self.calculation_mode == 'ADD': 410 new_vert_weight = pre_vert_weight + self.calculation_value 411 elif self.calculation_mode == 'SUB': 412 new_vert_weight = pre_vert_weight - self.calculation_value 413 elif self.calculation_mode == 'MULTI': 414 new_vert_weight = pre_vert_weight * self.calculation_value 415 elif self.calculation_mode == 'DIV': 416 new_vert_weight = pre_vert_weight / self.calculation_value 417 418 if new_vert_weight < 0.0: 419 new_vert_weight = 0.0 420 elif 1.0 < new_vert_weight: 421 new_vert_weight = 1.0 422 423 new_vert_weight = (pre_vert_weight * (1.0 - effect)) + (new_vert_weight * effect) 424 425 if 0.0 < new_vert_weight: 426 ob.vertex_groups.active.add([vert.index], new_vert_weight, 'REPLACE') 427 else: 428 ob.vertex_groups.active.remove([vert.index]) 429 430 bpy.ops.object.mode_set(mode=pre_mode) 431 for selected_object in pre_selected_objects: 432 compat.set_select(selected_object, True) 433 return {'FINISHED'}
Inherited Members
- bpy_types.Operator
- as_keywords
- poll_message_set
- builtins.bpy_struct
- keys
- values
- get
- pop
- as_pointer
- keyframe_insert
- keyframe_delete
- driver_add
- driver_remove
- is_property_set
- property_unset
- is_property_readonly
- is_property_overridable_library
- property_overridable_library_set
- path_resolve
- path_from_id
- type_recast
- bl_rna_get_subclass_py
- bl_rna_get_subclass
- id_properties_ensure
- id_properties_clear
- id_properties_ui
- id_data